package com.service.admin.base.controller;

import com.service.admin.base.controller.rep.WalletConfigRep;
import com.service.admin.base.controller.req.WalletConfigReq;
import com.service.admin.base.controller.req.WalletReq;
import com.service.admin.base.service.ConfigService;
import com.service.admin.base.service.WalletPoolService;
import com.service.admin.framework.log.RequestLog;
import com.service.admin.member.service.MemberRWService;
import com.service.admin.utils.WalletUtil;
import com.service.core.exception.CommonException;
import com.service.core.rest.BaseController;
import com.service.core.rest.request.PageRequest;
import com.service.core.rest.response.BaseResponse;
import com.service.core.rest.response.OneResponse;
import com.service.core.rest.response.PageResponse;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.web3j.crypto.RawTransaction;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.response.EthGetTransactionReceipt;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.protocol.http.HttpService;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;

/**
 * 钱包交易相关
 */
@Slf4j
@RestController
@RequestMapping("wallet")
public class WalletController extends BaseController {

    @Autowired
    private ConfigService configService;

    @Autowired
    private MemberRWService memberRWService;

    @Autowired
    private WalletPoolService walletPoolService;

    private Web3j web3j;

    @RequestLog("查询钱包配置")
    @ApiOperation("查询钱包配置")
    @PostMapping("config")
    public PageResponse<WalletConfigRep> configList(PageRequest pageRequest){
        return successQueryPageResponse(walletPoolService.configList(pageRequest));
    }

    @RequestLog("钱包初始化配置")
    @ApiOperation("钱包初始化配置")
    @PostMapping("initConfig")
    public BaseResponse initWalletConfig(@ApiParam @RequestBody WalletConfigReq walletConfigReq){
        walletPoolService.initWalletConfig(walletConfigReq);
        return successBaseResponse();
    }

    @RequestLog("创建钱包交易接口")
    @ApiOperation("创建钱包交易，生成未签名交易数据")
    @PostMapping("transaction")
    public OneResponse<Map<String, Object>> transaction(@ApiParam @RequestBody WalletReq walletReq) throws IOException {
        web3j = Web3j.build(new HttpService(configService.getETHNodeUrl()));

        switch (walletReq.getCoinType().getCode()){
            case 1:
                //USDT
                walletReq.setCoinAddress(configService.getERC20USDT().getConfValue());
                walletReq.setCoinDecimal(6.0);
                break;
            case 5:
                //EXDF
                walletReq.setCoinAddress(configService.getEXDF().getConfValue());
                walletReq.setCoinDecimal(9.0);
                break;
            default:
                //暂不支持其它交易
                throw new CommonException("暂不支持其它交易");
        }

        if (walletReq.getIfAll() == 1 && walletReq.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
            BigInteger allcoins = WalletUtil.getBalanceOfCoin(walletReq.getAddress(), walletReq.getCoinAddress(), web3j);
            walletReq.setAmount(WalletUtil.usdt_unit(allcoins));
        }else if(walletReq.getAmount().compareTo(BigDecimal.ZERO) <= 0){
            throw new CommonException("请填写要归集的金额");
        }

        BigDecimal amount = walletReq.getAmount();//金额
        if (StringUtils.isEmpty(walletReq.getTo())) {
            //前台没有传入交易目的钱包地址
            walletReq.setTo(configService.getETHCoinbase());//从数据库读管理员钱包地址
        }
        BigDecimal ethBalance = WalletUtil.getBalance(walletReq.getAddress(), web3j);
        BigInteger nonce = web3j.ethGetTransactionCount(walletReq.getAddress(), DefaultBlockParameterName.PENDING).send().getTransactionCount();
        BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice();
        BigInteger gasLimit = new BigInteger("210000");
        RawTransaction rawTransaction = WalletUtil.unsignedRawTransactionData(walletReq.getCoinAddress(), walletReq.getTo(), nonce, gasPrice, gasLimit, amount);
        HashMap<String, Object> map = new HashMap<>();
        map.put("ethBalance", ethBalance);
        map.put("rawTransaction", rawTransaction);
        return successQueryOneResponse(map);
    }


    /**
     * @param walletReq
     * @return
     */
    @RequestLog("提交已签名交易")
    @ApiOperation("创建钱包交易，提交已签名交易")
    @PostMapping("send")
    public BaseResponse sendRawTransaction(@ApiParam @RequestBody WalletReq walletReq,
                                           HttpServletResponse rep) {
        try {
            web3j = Web3j.build(new HttpService(configService.getETHNodeUrl()));

            EthSendTransaction ethSendTransaction = web3j.ethSendRawTransaction(walletReq.getSigned()).sendAsync().get();
            if (ethSendTransaction.hasError()) {
                String message = ethSendTransaction.getError().getMessage();
                throw new CommonException("提交失败，错误消息:" + message);
            } else {
                String hash = ethSendTransaction.getTransactionHash();
                EthGetTransactionReceipt send = web3j.ethGetTransactionReceipt(hash).send();
                //更新归集标志
                int row = memberRWService.funded(walletReq);
                if(row > 0){
                    log.info("成功归集：响应数据 {}", row);
                }
                log.info("成功交易：交易hash {} ,交易响应数据 {}", hash, send.toString());
                return successQueryOneResponse(hash);
            }
        } catch (Exception e) {
            throw new CommonException("提交失败，错误消息:" + e.getMessage());
        }
    }
}
